package copy.code;

import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import copy.express.pojo.EqualsNode;
import copy.express.pojo.NodeStack;
import copy.express.pojo.NodeType;
import copy.express.pojo.type.Type;
import copy.mark.EasyCopy;
import copy.meta.AbsParseMetaData;
import copy.pojo.IfMeta;
import copy.pojo.MethodMeta;
import copy.pojo.PropertyMeta;
import copy.scan.ScanStrategy;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.HashMap;
import java.util.Map;

/**
 * 类作用: 模板设计模式,控制流程
 *      生成字节码
 *
 *
 */
public abstract class AbsEasyCopyClassCode extends AbsTypetransformClassCode implements GenerateClassCode {
    public AbsEasyCopyClassCode(ProcessingEnvironment processingEnv) {
        super(processingEnv);
    }
    protected Map<Element,Map<JCTree.JCMethodDecl,List<JCTree.JCStatement>> > methodBodyMap = new HashMap<>();
    @Override
    public void process() throws ClassNotFoundException {
        //生成字节码: 类型转换器生成成员属性,单例对象
        genTransformSingleBean();
        //生成@EasyCopy中字节码
        genClassCode();

    }
    public boolean isMethodCondition(NodeStack conditionNodeStack){
        for (int i = 0; i < conditionNodeStack.size(); i++) {
            NodeType n = (NodeType)conditionNodeStack.get(i);
            if (n instanceof EqualsNode){
                return true;
            }
        }
        return false;
    }

    public JCTree.JCExpressionStatement parseNodeStack(NodeStack nodeStack,JCTree.JCMethodDecl methodDecl,PropertyMeta propertyMeta){
        //判断NodeStack个数,只有一个
        JCTree.JCExpressionStatement resStatement;
        if (nodeStack.getQueue().size() == 1){
            resStatement = getExpressionStateByNode(  nodeStack.getQueue().pop(), methodDecl);
        }else{//判断NodeStack个数,如果大于等于1
            resStatement = getExpressionStateByNodeStack( methodDecl, propertyMeta, nodeStack);
        }
        return  resStatement;
    }
    /**
     * 字节码表达式: 处理类型转换
     *
     * @param getResultExpress 结果表达式
     * @param caseTypeStr 转换的方式
     * @return
     */
    public  JCTree.JCExpression  cast(JCTree.JCExpression getResultExpress, String caseTypeStr, NodeStack castStack, JCTree.JCMethodDecl methodDecl, PropertyMeta propertyMeta){
        if ( caseTypeStr == null || "".equals(caseTypeStr)){
            return getResultExpress;
        }
        //情况1: Integer.valueOf() 或 String.valueOf()
        ListBuffer<JCTree.JCExpression> expressionList = new ListBuffer<>();
        if (castStack != null ){
            for (int i = 0; i < castStack.size(); i++) {
                NodeType nodeType = (NodeType)castStack.get(i);
                if (nodeType.getType() instanceof Type.FieldType){
                    Type.FieldType fieldType = (Type.FieldType)nodeType.getType();
                    if (fieldType == Type.FieldType.SELF){
                        expressionList.add(getResultExpress);
                        continue;
                    }
                }
                expressionList.add( getExpressionStateByNode(nodeType,methodDecl).expr );
            }
            caseTypeStr = caseTypeStr.substring( 0 , caseTypeStr.indexOf("(") );
            String[] split = caseTypeStr.split("\\.");
            return doExeMethodByClassName(split[0], split[1], expressionList.toList() ).expr;
        }
        //情况2: int a = (int)1.1;
        TypeTag typeTag = castTypeMap.get(caseTypeStr);
        if (typeTag != null){
            return treeMaker.TypeCast(treeMaker.TypeIdent(typeTag), getResultExpress);
        }
        //情况3: Person p = (Person)teacher;
        return treeMaker.TypeCast(treeMaker.Ident(names.fromString(caseTypeStr)), getResultExpress);
    }
    /**
     * 这个方法,显得有点多余
     */
    public void genClassCode(){

        for (Element e : ScanStrategy.easycopyMap.values()) {
            methodBodyMap.putIfAbsent(e,new HashMap<>());
            ScanStrategy.easycopyMap.put("",(TypeElement) e);
            //添加导包
            addImportInfo(e,"java.util","HashMap");
            addImportInfo(e,"copy.type","BigDecimalType");
            //导入所有类型转换器的包
            for (String typeTransformClass : ScanStrategy.typetransformMap.keySet()) {
                String pack = typeTransformClass.substring(0,typeTransformClass.lastIndexOf("."));
                String className = typeTransformClass.substring(typeTransformClass.lastIndexOf(".")+1);
                addImportInfo(e,pack,className);
            }
            //导入第三方工具类的包
            EasyCopy easyCopyAnno = e.getAnnotation(EasyCopy.class);
            for (String packageNames : easyCopyAnno.packageNames()) {
                String pack = packageNames.substring(0,packageNames.lastIndexOf("."));
                String className = packageNames.substring(packageNames.lastIndexOf(".")+1);
                addImportInfo(e,pack,className);
            }
            JCTree tree = javacTrees.getTree(e);
            //添加访问事件
            tree.accept(new TreeTranslator(){
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    //多个方法
                    Map<JCTree.JCMethodDecl, List<JCTree.JCStatement>> methodMap = methodBodyMap.get(e);
                    for (JCTree it : jcClassDecl.defs) {

                        if (it.getKind().equals(Tree.Kind.METHOD)){
                            JCTree.JCMethodDecl methodDecl =  (JCTree.JCMethodDecl)it;
                            List<JCTree.JCAnnotation> annotations = methodDecl.getModifiers().getAnnotations();
                            if ( annotations != null && annotations.size() > 0 && annotations.get(0).getAnnotationType().toString().equals("ParamMaps") ){
                                //it2.getModifiers().getAnnotations()

                                //接口全限定类名 获取HashMap中MethodMeda
                                Map<String, MethodMeta> interfaceMetaDataList = AbsParseMetaData.interfaceMetaDataMap.get(e.toString());
                                //方法名称 获取MethodMeda
                                MethodMeta methodMeta = interfaceMetaDataList.get(methodDecl.getName().toString());
                                try {
                                    //methodDecl.mods.flags = (Flags.PUBLIC + Flags.STATIC);
                                    ListBuffer<JCTree.JCStatement> statments = new ListBuffer<JCTree.JCStatement>();
                                    //开始处理属性映射
                                    for (PropertyMeta propertyMeta : methodMeta.getPropertyMetas()) {
                                        //查找有无自定义的类型抓换: 将转换器中方法体,加入到字节码中
                                        String typeTransformStr = propertyMeta.getTypeTransform();
                                        //JCTree.JCExpressionStatement setResultExpression = setField(propertyMeta.getTargetPropertyName(), method, getResultExpression.expr);
                                        //如果存在自定义的属性转换器
                                        if (typeTransformStr != null ) {
                                            JCTree.JCExpressionStatement resStatement = genTypetransformCLassCode(statments, methodDecl, propertyMeta);
                                            resStatement.expr = cast(resStatement.expr,propertyMeta.getCast(),propertyMeta.getCastStack(),methodDecl, propertyMeta);
                                            JCTree.JCExpressionStatement setExpressionStatement = setField(propertyMeta.getTargetPropertyName(), methodDecl,resStatement.expr);
                                            statments.append(setExpressionStatement);
                                        } else{//如果不存在自定义的属性转换器
                                            //不是三元表达式
                                            if (propertyMeta.getIfMeta()==null){
                                                NodeStack nodeStack = propertyMeta.getNodeStack();
                                                JCTree.JCExpressionStatement resStatement = parseNodeStack(nodeStack, methodDecl, propertyMeta);
                                                resStatement.expr = cast(resStatement.expr,propertyMeta.getCast(),propertyMeta.getCastStack(),methodDecl,propertyMeta );
                                                JCTree.JCExpressionStatement setExpressionStatement = setField(propertyMeta.getTargetPropertyName(), methodDecl,resStatement.expr);
                                                statments.append(setExpressionStatement);
                                            }else{//这是一个三元表达式
                                                IfMeta ifMeta = propertyMeta.getIfMeta();
                                                //条件判断
                                                NodeStack conditionNodeStack = ifMeta.getConditionNodeStack();
                                                JCTree.JCExpressionStatement conditionStatement = null;
                                                conditionStatement = parseNodeStack(conditionNodeStack, methodDecl, propertyMeta);
                                                //true结果表达式
                                                NodeStack trueNodeStack = ifMeta.getTrueNodeStack();
                                                JCTree.JCExpressionStatement trueStatement = null;
                                                trueStatement = parseNodeStack(trueNodeStack, methodDecl, propertyMeta);
                                                trueStatement.expr = cast( trueStatement.expr,propertyMeta.getCast(),propertyMeta.getCastStack(),methodDecl,propertyMeta );
                                                JCTree.JCExpressionStatement setTrueExpressionStatement = setField(propertyMeta.getTargetPropertyName(), methodDecl,trueStatement.expr);
                                                //false结果表达式
                                                NodeStack falseNodeStack = ifMeta.getFalseNodeStack();
                                                JCTree.JCExpressionStatement falseStatement = null;
                                                falseStatement = parseNodeStack(falseNodeStack, methodDecl, propertyMeta);
                                                falseStatement.expr = cast( falseStatement.expr,propertyMeta.getCast(),propertyMeta.getCastStack(),methodDecl,propertyMeta );
                                                JCTree.JCExpressionStatement setFalseExpressionStatement = setField(propertyMeta.getTargetPropertyName(), methodDecl,falseStatement.expr);
                                                //生成if判断
                                                JCTree.JCIf anIf = treeMaker.If(
                                                        conditionStatement.expr, // if语句里面的判断语句
                                                        setTrueExpressionStatement, // 条件成立的语句
                                                        setFalseExpressionStatement  // 条件不成立的语句
                                                );
                                                statments.append(anIf);
                                            }

                                        }
                                    }
                                    //添加返回语句
                                    JCTree.JCReturn returnStatement = treeMaker.Return(
                                            treeMaker.Ident( methodDecl.params.get(0).getName() )
                                    );


                                    statments.append(returnStatement);
                                    //将语句设置到方法体中
                                   // methodDecl.body = treeMaker.Block(0,statments.toList());
                                    methodMap.put(methodDecl,statments.toList());

                                } catch (Exception e){
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                    super.visitClassDef(jcClassDecl);
                    createClass(jcClassDecl);
                    //生成当前类的子类

                }
            });


            //添加访问事件
            tree.accept(new TreeTranslator(){
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    //多个方法
                    Map<JCTree.JCMethodDecl, List<JCTree.JCStatement>> methodMap = methodBodyMap.get(e);
                    for (JCTree it : jcClassDecl.defs) {

                        if (it.getKind().equals(Tree.Kind.INTERFACE)){
                           createClass(jcClassDecl);
                        }
                    }
                    super.visitClassDef(jcClassDecl);


                }
            });
        }
    }


}
